package com.iretailer.report.analyze.device.face.faceapi;

import com.alibaba.fastjson.JSON;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.RemovalListener;
import com.google.common.cache.RemovalNotification;
import com.iretailer.report.analyze.commonModel.InOutMetric;
import com.iretailer.report.analyze.commonModel.PassengerFlowModel;
import com.iretailer.report.analyze.flow.FlowInsert;
import com.iretailer.report.model.FaceAlarm;
import com.iretailer.report.util.StringUtil;
import com.iretailer.report.util.TimeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Auther: xjw
 * @Date: 2019/11/28 0028 11:26
 * @Description:
 */
@Component
public class FaceApiFlow {
    private static final Logger log = LoggerFactory.getLogger(FaceApiFlow.class);
    private static final FlowInnerClass defaultLock = new FlowInnerClass(-1, null);
    private static FlowInsert flowInsert;

    // 给静态变量赋值
    @Autowired
    public void setFlowInsert(FlowInsert flowInsert) {
        this.flowInsert = flowInsert;
    }

    // key 为 deviceId_LocalDateTime
    private static final Cache<String, FlowInnerClass> cache = CacheBuilder.newBuilder()
            .expireAfterWrite(60, TimeUnit.SECONDS)
            .removalListener(new RemovalListener<String, FlowInnerClass>() {
                @Override
                public void onRemoval(RemovalNotification<String, FlowInnerClass> remove) {
                    if (remove.wasEvicted()) {
                        PassengerFlowModel pfm = faceApi2PFM(remove.getValue());
                        log.error("{} {}", remove.getKey(), cache.stats());
                        log.error("---- {} flowapi flow {} {}", LocalDateTime.now(), remove.getKey(), JSON.toJSONString(pfm));
                        if (pfm != null) {
                            flowInsert.analysisCommon(pfm);
                        }
                    }
                }
            })
            .recordStats()
            .build();


    public void pushFlow(FaceApi faceApi) {
        if (faceApi != null && StringUtil.notEmpty(faceApi.getDeviceId())) {
            String deviceId = faceApi.getDeviceId();
            LocalDateTime t = faceApi.getTime();
            String time = TimeUtil.localDateTime_format(LocalDateTime.of(t.getYear(), t.getMonth(), t.getDayOfMonth(), t.getHour(), t.getMinute(), 0), "YYYYMMddHHmmss");
            String key = String.format("%s_%s", deviceId, time);
            FlowInnerClass flowInnerClass = cache.getIfPresent(key);
            FlowInnerClass lock = flowInnerClass == null ? defaultLock : flowInnerClass;
            synchronized (lock) {
                // 再次获取
                flowInnerClass = cache.getIfPresent(key);
                log.error("--- {} lock = {}",key,lock.enter);
                if (flowInnerClass == null) {
                    flowInnerClass = new FlowInnerClass(0, faceApi);
                }
                flowInnerClass.enter += 1;
                cache.put(key, flowInnerClass);
            }
        }
    }


    public static PassengerFlowModel faceApi2PFM(FlowInnerClass flowInnerClass) {
        FaceApi faceApi = flowInnerClass.faceApi;
        if (StringUtil.notEmpty(faceApi.getDeviceId())) {
            PassengerFlowModel pfm = new PassengerFlowModel();
            pfm.setDeviceId(faceApi.getDeviceId());
            pfm.setDeviceName(faceApi.getDeviceName());
            pfm.setMacAddress(faceApi.getMacAddress());
            pfm.setIpAddress(faceApi.getIpAddress());
            pfm.setDeviceType("FaceApi");
            pfm.setSerialNumber("");
            InOutMetric inOutMetric = new InOutMetric();
            inOutMetric.setZone("0");
            LocalDateTime t = faceApi.getTime();
            LocalDateTime endDateTime = LocalDateTime.of(t.getYear(), t.getMonth(), t.getDayOfMonth(), t.getHour(), t.getMinute(), 0);
            inOutMetric.setDate(endDateTime.toLocalDate());
            inOutMetric.setStartTime(endDateTime.toLocalTime());
            inOutMetric.setEndTime(endDateTime.toLocalTime().minusMinutes(1));
            inOutMetric.setEnter(flowInnerClass.enter);
            inOutMetric.setExit(0);
            pfm.setInOutMetrics(Arrays.asList(inOutMetric));
            return pfm;
        } else {
            return null;
        }
    }

    private static class FlowInnerClass {
        private int enter;
        private FaceApi faceApi;

        public FlowInnerClass(int enter, FaceApi faceApi) {
            this.enter = enter;
            this.faceApi = faceApi;
        }
    }

}
